<template>
  <div class="event-pane">
    <div class="event-tool-bar">
      <el-button type="primary" :icon="Plus" text @click="addEventBinding">添加绑定</el-button>
    </div>
    <el-scrollbar height="calc(100vh - 208px)">
      <div class="event-binding-list">
        <div class="event-binding-row" v-for="(bind, index)  in loadBindings" :key="bind.event">
          <div class="item">
            <span>{{ bind.eventName }} → {{ bind.targetMethodName }}</span>
          </div>
          <div>
            <el-button type="primary" :icon="Edit" text @click.stop="editEventBinding(bind)">编辑</el-button>
            <el-button type="danger" :icon="Delete" text @click.stop="removeEventBinding(index)">移除</el-button>
          </div>
        </div>
      </div>
    </el-scrollbar>

    <!-- 事件绑定对话框 -->
    <el-dialog 
      v-model="dialogVisible" 
      :title="isEditing ? '编辑事件绑定' : '添加事件绑定'" 
      width="800px"
	  :close-on-click-modal="false"
	  draggable
      @close="resetDialog"
    >
      <el-form>
        <el-form-item label="组件事件">
          <el-select v-model="newEvent.event" placeholder="请选择组件事件" @change="handleEventChange">
            <el-option 
              v-for="item in bindTargetEvents" 
              :key="item.identifier" 
              :label="item.name" 
              :value="item.identifier" 
            />
          </el-select>
        </el-form-item>
        <el-form-item label="绑定组件">
          <el-tree-select
            v-model="newEvent.target"
            :data="props.structure"
            :props="treeProps"
            node-key="id"
            @check-change="handleBindChange"
            :render-after-expand="false"
			:show-checkbox="true"
			:check-on-click-node="true"
			:check-strictly="true"
            placeholder="请选择绑定组件"
          />
        </el-form-item>
		
        <el-form-item label="联动方法">
          <el-select 
            v-model="newEvent.targetMethod" 
            placeholder="请选择绑定对象方法"
            :disabled="!newEvent.target"
			@change="handleTargetMethodChange"
			v-if="bindTargetMethods.length>0"
          >	
            <el-option 
              v-for="item in bindTargetMethods" 
              :key="item.identifier" 
              :label="item.name" 
              :value="item.identifier" 
            />
          </el-select>
		  <div v-else class="el-select__wrapper" style="width: 100%;">
			  {{newEvent.targetMethodName}}
		  </div>
        </el-form-item>

        <el-form-item label="参数映射">
          <div class="mapping-container">
            <div class="event-tool-bar">
              <el-button 
                type="primary" 
                :icon="Plus" 
                text 
                @click="openAddFieldMappingDialog"
                :disabled="!newEvent.targetMethod"
              >
                添加映射
              </el-button>
            </div>
            
            <div class="event-binding-list">
              <div class="event-binding-row" v-for="(mapping, index) in newEvent.params" :key="index">
                <div class="item">
                  <span>{{ mapping.sourceName }} → {{ mapping.targetName }}</span>
                </div>
                <div>
                  <el-button type="primary" :icon="Edit" text @click.stop="editFieldMapping(index)">编辑</el-button>
                  <el-button type="danger" :icon="Delete" text @click.stop="removeFieldMapping(index)">移除</el-button>
                </div>
              </div>
            </div>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button 
          type="primary" 
          @click="confirmAddEventBinding" 
          :disabled="!isFormValid"
        >
          确定
        </el-button>
      </template>
    </el-dialog>

    <!-- 参数映射对话框 -->
    <el-dialog 
      v-model="fieldMappingDialogVisible" 
      :title="isEditingMapping ? '编辑参数映射' : '添加参数映射'" 
      width="600px"
	  :close-on-click-modal="false"
	  draggable
    >
      <el-form :model="currentMapping">
        <el-form-item label="事件参数">
		  <el-tree-select
		    v-model="currentMapping.source"
		    :data="eventParams"
		    :props="treeParamProps"
		    node-key="identifier"
		  			:show-checkbox="true"
		  			:check-on-click-node="true"
		  			:check-strictly="true"
		  			 @check-change="handleEventSourceClick"
		    placeholder="请选择事件参数"
		  />
		  
        </el-form-item>
        <el-form-item label="方法参数">
		  <el-tree-select
		    v-model="currentMapping.target"
		    :data="targetMethodParams"
		    :props="treeParamProps"
		    node-key="identifier"
			:show-checkbox="true"
			:check-on-click-node="true"
			:check-strictly="true"
			 @check-change="handleTargetMethodClick"
		    placeholder="请选择目标方法参数参数"
		  />
        </el-form-item>
		
		
      </el-form>
      <template #footer>
        <el-button @click="fieldMappingDialogVisible = false">取消</el-button>
        <el-button 
          type="primary" 
          @click="confirmFieldMapping"
          :disabled="!currentMapping.source || !currentMapping.target"
        >
          确定
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, computed, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { reactive } from 'vue-demi'
import { Check, Delete, Plus, Edit } from '@element-plus/icons-vue'
import { ComponentInstance } from '@/types/visual-app'
import { ComponentLibraryService } from '@/api/visual/componentLibraryApi'

const props = defineProps<{ 
  type: string,
  component?: ComponentInstance,
  structure: any ,
  bindings:any[]
}>()

const treeProps = { label: 'label', children: 'children' }

const treeParamProps = { label: 'name', children: 'children' }

const emit = defineEmits<{
  (e: 'bindings', bindings: any): void
}>()

const lifecycleStages = [
  {
    identifier: 'beforeCreate',
    name: '创建之前',
    outputData: [],
    description: '实例初始化之后，数据观测和事件配置之前调用'
  },
  {
    identifier: 'created',
    name: '创建完成',
    outputData: [],
    description: '实例创建完成后调用，可以访问data、methods等'
  },
  {
    identifier: 'beforeMount',
    name: '挂载之前',
    outputData: [],
    description: '在挂载开始之前调用，模板编译已完成'
  },
  {
    identifier: 'mounted',
    name: '挂载完成',
    outputData: [],
    description: '实例挂载后调用，DOM已渲染完成'
  },
  {
    identifier: 'beforeUpdate',
    name: '更新之前',
    outputData: [],
    description: '数据变化时，虚拟DOM重新渲染之前调用'
  },
  {
    identifier: 'updated',
    name: '更新完成',
    outputData: [],
    description: '数据更改导致虚拟DOM重新渲染后调用'
  },
  {
    identifier: 'beforeUnmount',
    name: '卸载之前',
    outputData: [],
    description: '实例销毁之前调用，适合清理工作'
  },
  {
    identifier: 'unmounted',
    name: '卸载完成',
    outputData: [],
    description: '实例销毁后调用，所有指令已解绑'
  },
  {
    identifier: 'errorCaptured',
    name: '错误捕获',
    outputData: [],
    description: '捕获来自子孙组件的错误'
  },
  {
    identifier: 'renderTracked',
    name: '渲染跟踪',
    outputData: [],
    description: '调试钩子，跟踪组件重新渲染(Vue3特有)'
  },
  {
    identifier: 'renderTriggered',
    name: '渲染触发',
    outputData: [],
    description: '调试钩子，跟踪组件重新渲染(Vue3特有)'
  }
]


const groupMethods = [
  {
    identifier: 'fadeLeftAnimationend',
    name: '左侧淡入淡出',
	type:'group',
    outputData: [],
    description: '左侧淡入淡出'
  },
  {
    identifier: 'fadeRightAnimationend',
    name: '右侧淡入淡出',
	type:'group',
    outputData: [],
    description: '右侧淡入淡出'
  }
]

const groupEvents = [
  {
    identifier: 'fadeInLeftAnimationend',
    name: '左侧淡入结束',
	type:'group',
    outputData: [],
    description: '左侧淡入结束'
  },
  {
    identifier: 'fadeOutLeftAnimationend',
    name: '左侧淡出结束',
	type:'group',
    outputData: [],
    description: '左侧淡出结束'
  },
  {
    identifier: 'fadeInRightAnimationend',
    name: '右侧淡入结束',
	type:'group',
    outputData: [],
    description: '右侧淡入结束'
  },
  {
    identifier: 'fadeOutRightAnimationend',
    name: '右侧淡出结束',
	type:'group',
    outputData: [],
    description: '右侧淡出结束'
  }
]

// 事件绑定列表
const loadBindings = ref<any[]>(Array.isArray(props?.bindings) ? [...props.bindings] : [])
const editingIndex = ref<number | null>(null)
const isEditing = computed(() => editingIndex.value !== null)

// 弹窗相关
const dialogVisible = ref(false)
const newEvent = reactive({
  event: '',
  eventName: '',
  target: '',
  targetMethod: '',
  targetMethodName: '',
  targetType:'',
  methodDefParams:undefined,
  params: [] as Array<{
	  source: string, 
	  target: string,
	  pSource: string,
	  pTarget: string,
	  sourceName: string,
	  targetName: string
	}>
})

// 参数映射相关
const fieldMappingDialogVisible = ref(false)
const currentMappingIndex = ref<number | null>(null)
const isEditingMapping = computed(() => currentMappingIndex.value !== null)
const currentMapping = reactive({
  pSource: '',
  source: '',
  sourceName:'',
  pTarget: '',
  target: '',
  targetName: '',
})

// 可绑定事件和方法
const bindTargetEvents = ref<any[]>([])
const bindTargetMethods = ref<any[]>([])

// 表单验证
const isFormValid = computed(() => {
  return newEvent.event && newEvent.target && newEvent.targetMethod
})

// 初始化组件事件
const initComponentEvents = async () => {
	if(props.type=='page'){
		bindTargetEvents.value=lifecycleStages;
	}
	else if(props.type=='group'){
		bindTargetEvents.value=groupEvents;
	}
	else if(props.type=='component' && props.component?.componentId){
		bindTargetEvents.value = await ComponentLibraryService.getComponentDataModels(props.component?.componentId, 'event')
	}else{
		console.warn("【"+props.type+'】未知.');
	}
}

// 获取组件方法
const getMethods = async (componentId: string) => {
  bindTargetMethods.value = await ComponentLibraryService.getComponentDataModels(componentId, 'method')
  newEvent.targetMethod = '' // 重置选择的方法
  newEvent.targetMethodName=''
  newEvent.methodDefParams=undefined;
  newEvent.targetType=''
  
}

const handleBindChange=(data :any ,ckecked:boolean,child :any)=>{
	if(ckecked){
	  if (data.type === 'component') {
			getMethods(data.componentId)
	  } else if (data.type === 'group') {
			bindTargetMethods.value=groupMethods
	  }
	}
}


// 处理事件变化
let eventParams: any[]=[];
const handleEventChange = (val:string) => {
	const selected = bindTargetEvents.value.find(e => e.identifier === val)
	if(selected){
		newEvent.eventName=selected.name;
		const outputData = typeof selected.outputData === 'string' ? JSON.parse(selected.outputData) : []
		let childrens: any[]=[];
		for(var item of outputData){
			let children={}
			getChildrens(children,item);
			childrens.push(children);
		}
		eventParams=childrens;
	}else{
		eventParams=[]
	}
}

let targetMethodParams: any[]=[];
const handleTargetMethodChange = (val:string) => {
	const selected = bindTargetMethods.value.find(e => e.identifier === val)
	if(selected){
		newEvent.targetMethodName=selected.name;
		const inputData = typeof selected.inputData === 'string' ? JSON.parse(selected.inputData) : []
		let childrens: any[]=[];
		for(var item of inputData){
			let children={}
			getChildrens(children,item);
			childrens.push(children);
		}
		targetMethodParams=childrens;
		newEvent.methodDefParams=inputData;
		
		if(selected.hasOwnProperty('type')){
			newEvent.targetType=selected.type;
		}
	}
	else{
		targetMethodParams=[]
		newEvent.targetType='';
		newEvent.methodDefParams=undefined;
	}
}

const getChildrens=(children:any,item:any)=>{
	children['name']=item.name
	children['identifier']=item.identifier
	if(item.dataType.type=='struct' && item.dataType.specs){
		let childrens: any[]=[];
		for(var spec of item.dataType.specs){
			let child={
				pidentifier:children.hasOwnProperty('pidentifier')? children['pidentifier']+','+item.identifier:item.identifier
			}
			getChildrens(child,spec)
			childrens.push(child);
		}
		children['children']=childrens;
	}
	return children;
}

const handleTargetMethodClick=(data :any ,ckecked:boolean,child :any)=>{
	if(ckecked){
		if(data.hasOwnProperty('pidentifier')){
			currentMapping.pTarget=data.pidentifier
		}
		currentMapping.targetName=data.name
	}else{
		currentMapping.pTarget=''
	}
}

const handleEventSourceClick=(data :any ,ckecked:boolean,child :any)=>{
	if(ckecked){
		if(data.hasOwnProperty('pidentifier')){
			currentMapping.pSource=data.pidentifier
		}
		currentMapping.sourceName=data.name
	}else{
		currentMapping.pSource=''
	}
}

// 添加事件绑定
const addEventBinding = () => {
  editingIndex.value = null
  resetNewEvent()
  dialogVisible.value = true
  initComponentEvents()
}

// 编辑事件绑定
const editEventBinding = (row: any) => {
  editingIndex.value = loadBindings.value.findIndex(b => b.event === row.event)
  Object.assign(newEvent, JSON.parse(JSON.stringify(row)))
  dialogVisible.value = true
  initComponentEvents()
}

// 移除事件绑定
const removeEventBinding = async (index: any) => {
  try {
    await ElMessageBox.confirm('确定要移除该事件绑定吗?', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
	loadBindings.value.splice(index, 1)
    ElMessage.success('移除成功')
	emit('bindings', loadBindings.value);
  } catch {
    // 用户取消
  }
}

// 确认添加/编辑事件绑定
const confirmAddEventBinding = () => {
  if (!isFormValid.value) return
  
  const eventBinding = {
    event: newEvent.event,
	eventName:newEvent.eventName,
    target: newEvent.target,
    targetMethod: newEvent.targetMethod,
	targetMethodName:newEvent.targetMethodName,
	methodDefParams:newEvent.methodDefParams,
	targetType:newEvent.targetType,
    params: [...newEvent.params]
  }
  
  if (isEditing.value) {
    loadBindings.value[editingIndex.value!] = eventBinding
  } else {
    loadBindings.value.push(eventBinding)
  }

  dialogVisible.value = false
  ElMessage.success(isEditing.value ? '更新成功' : '添加成功')
  
  emit('bindings', loadBindings.value);
}

// 打开添加参数映射对话框
const openAddFieldMappingDialog = () => {
  currentMappingIndex.value = null
  currentMapping.source = ''
  currentMapping.target = ''
  fieldMappingDialogVisible.value = true
}

// 编辑参数映射
const editFieldMapping = (index: number) => {
  currentMappingIndex.value = index
  currentMapping.source = newEvent.params[index].source
  currentMapping.target = newEvent.params[index].target
  currentMapping.pSource = newEvent.params[index].pSource
  currentMapping.pTarget = newEvent.params[index].pTarget
  currentMapping.sourceName = newEvent.params[index].sourceName
  currentMapping.targetName = newEvent.params[index].targetName
  fieldMappingDialogVisible.value = true
}

// 移除参数映射
const removeFieldMapping = (index: number) => {
  newEvent.params.splice(index, 1)
}

// 确认参数映射
const confirmFieldMapping = () => {
  const mapping = {
    source: currentMapping.source,
    target: currentMapping.target,
	pSource: currentMapping.pSource,
	pTarget: currentMapping.pTarget,
	sourceName: currentMapping.sourceName,
	targetName: currentMapping.targetName,
  }

  if (isEditingMapping.value) {
		newEvent.params[currentMappingIndex.value!] = mapping
  } else {
		newEvent.params.push(mapping)
  }
  fieldMappingDialogVisible.value = false
}

// 重置对话框
const resetDialog = () => {
  editingIndex.value = null
  resetNewEvent()
}

// 重置新事件
const resetNewEvent = () => {
  newEvent.event = ''
  newEvent.target = ''
  newEvent.targetMethod = ''
  newEvent.params = []
}

watch(() => props?.bindings, (val) => {
	loadBindings.value = Array.isArray(val) ? [...val] : []
}, { immediate: true, deep: true })

</script>

<style scoped>
.event-pane {
  .event-tool-bar {
    height: 35px;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    margin-bottom: 5px;
    border-left: 2px solid #5d87ff;
    background: #5d87ff21;
    padding: 0 10px;
  }
  
  .event-binding-list {
    .event-binding-row {
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: 13px;
      background: rgba(0, 0, 0, 0.05);
      padding: 0px 8px 0px 8px;
      margin-bottom: 5px;
      border-radius: 4px;
      
      .item {
        flex: 1;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }
}

.mapping-container {
  width: 100%;
/*  border: 1px solid #eee; */
  border-radius: 4px;
/*  padding: 10px; */
  
  .event-binding-list {
    margin-top: 10px;
    max-height: 200px;
    overflow-y: auto;
  }
}
</style>